package hello.word.m2.maven.jpa.builder;

import hello.word.m2.maven.jpa.JpqlBuilder;
import hello.word.m2.maven.jpa.PartTree;
import org.jdbi.v3.core.config.ConfigRegistry;

import javax.persistence.Table;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class DefaultJpqlBuilder implements JpqlBuilder {

	private static final String QUERY_PATTERN ="find|read|get|steam";
	private static final Pattern PREFIX_TEMPLATE = Pattern.compile("^("+QUERY_PATTERN+")((\\p{Lu}.*?))??By");

	private ConcurrentHashMap<String,PartTree> methodMap = new ConcurrentHashMap<>();

	@Override
	public String build(Class<?> sqlObjectType, Method method, ConfigRegistry config) {
		Class<?> entityClass = extractSqlObjectType(sqlObjectType);
		Table table = entityClass.getAnnotation(Table.class);
		String tableName = table == null ? entityClass.getSimpleName(): table.name();
		String source = method.getName();
		Matcher matcher = PREFIX_TEMPLATE.matcher(source);

		if(matcher.find()){
			// methodMap to cache
			String key = entityClass.getName()+":"+source;
			PartTree tree =methodMap.computeIfAbsent(key,k ->
				 new PartTree(source.substring(matcher.group().length()),entityClass)

			);
//			PartTree tree = new PartTree(source,entityClass);
			return createSql(tableName, tree);
		}else {
			throw new IllegalStateException("Illegal method name "+source);
		}
//		Optional<String> name=this.getColumnName(entityClass,"tName");
//		System.out.println(name.orElseThrow(() ->new IllegalStateException("")));

	}

	private String createSql(String tableName, PartTree tree) {
		StringBuilder sql = new StringBuilder();
		sql.append("select * from ").append(tableName)
				.append(" where 1=1 and ")
				.append(tree.getSql());
		return sql.toString();
	}



	private Class<?> extractSqlObjectType(Class<?> sqlObjectType) {
		// TODO Auto-generated method stub
		ParameterizedType parameterizedType = (ParameterizedType) sqlObjectType
				.getGenericInterfaces()[0];
		Type type = parameterizedType.getActualTypeArguments()[0];
		Class<?> clazz=(Class<?>)type;
		return clazz;
	}
	
}
